package org.lisy.java.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

import com.alibaba.easyexcel.support.cglib.proxy.Enhancer;
import com.alibaba.easyexcel.support.cglib.proxy.MethodInterceptor;
import com.alibaba.easyexcel.support.cglib.proxy.MethodProxy;

/**
 * 代理
 * 
 * @author lisy
 */
public class ProxyOperate {

	public static void main(String[] args) {
		/**
		 * 静态代理 在编译期确定
		 */
		staticProxy();
		
		/**
		 * 动态代理 在运行期动态生成
		 * 反射是动态代理的一种实现方式
		 * java、Spring AOP 中的动态代理主要有两种方式:
		 * 1. JDK 动态代理：java.lang.reflect 包中的 Proxy 类和 InvocationHandler 接口提供了生成动态代理类的能力
		 * 2. Cglib 动态代理：Cglib (Code Generation Library )是一个第三方代码生成类库，运行时在内存中动态生成一个子类对象从而实现对目标对象功能的扩展 
		 */
		
		jdkDynamicProxy();
		
		cglibDynamicProxy();
	}

	private static void cglibDynamicProxy() {
		/**
		 * CGLIB 是一个代码生成的类库，可以在运行时动态 的生成某个类的子类
		 * 注意: CGLIB 是通过继承的方式做的动态代理，因此被标记为 final 的类无法使用 CGLIB 做动态代理
		 */
		CglibProxy proxy = new CglibProxy();
		PersonSerivice proxyServer = (PersonSerivice)proxy.getProxy(PersonSeriviceImpl.class);
		proxyServer.say();
	}

	private static void jdkDynamicProxy() {
		/**
		 * JDK 的动态代理有一个限制，就是使用动态代理的对象必须实现一个或多个接口
		 */
		PersonSeriviceImpl target = new PersonSeriviceImpl();
		MyInvocationHandler handler = new MyInvocationHandler(target);
		PersonSerivice proxy = (PersonSerivice) handler.getProxy();
		proxy.say();
	}

	private static void staticProxy() {
		/**
		 * 用途:
		 * 控制真实对象的访问权限 通过代理对象控制对真实对象的使用权限
		 * 避免创建大对象 通过使用一个代理小对象来代表一个真实的大对象，可以减少系统资源的消耗，对系统进行优化并提高运行速度
		 * 增强真实对象的功能
		 */
		PersonSerivice target = new PersonSeriviceImpl();
		PersonSeriviceProxy proxy = new PersonSeriviceProxy(target); 
		proxy.say();
	}
}

interface PersonSerivice {
	public void say();
}

class PersonSeriviceImpl implements PersonSerivice {
	@Override 
	public void say() {
		System.out.println("hello world !");
	}
}

class PersonSeriviceProxy implements PersonSerivice{
	private PersonSerivice target;
	
	public PersonSeriviceProxy(PersonSerivice target) {
		this.target = target;
	}
	
	@Override
	public void say() {
		System.out.println("static proxy:");
		target.say();
		System.out.println("static end.");
	}
}

class MyInvocationHandler implements InvocationHandler {
	 
	private Object target;
	
	public MyInvocationHandler(Object target) { 
		super();
		this.target = target; 
	}
 
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        saveStart();
        Object obj = method.invoke(target, args);
        saveDone();
        return obj;
    }
 
    public void saveStart(){
        System.out.println("jdk proxy:");
    }
 
    public void saveDone(){
        System.out.println("jdk end.");
    }
    
    public Object getProxy(){ 
    	return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), 
    			target.getClass().getInterfaces(), this);
    }
}

class CglibProxy implements MethodInterceptor {
	
	// 1.创建增强器
	private Enhancer enhancer = new Enhancer();
	
	public Object getProxy(Class<?> clazz){ 
		 // 2.设置父类
		enhancer.setSuperclass(clazz);
		// 3.设置回调
		enhancer.setCallback(this); 
		// 4.设置代理对象，通过字节码技术动态创建子类实例
		return enhancer.create(); 
	}

	@Override
	public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
		System.out.println("cglib proxy:");
		Object result = proxy.invokeSuper(obj, args);
		System.out.println("cglib end.");
		return result;
	}
}
